#include "PSFMaterials.hh"

#include "G4NistManager.hh"
#include "G4SystemOfUnits.hh"

PSFMaterials *PSFMaterials::fInstance = nullptr;

//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......

PSFMaterials::PSFMaterials()
{
  fNistMan = G4NistManager::Instance();
  fNistMan->SetVerbose(2);

  CreateMaterials();
}

//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......

PSFMaterials::~PSFMaterials()
{
  delete fAir;
  delete fPMMA;
  delete fPethylene;
  delete fFPethylene;
  delete fPolystyrene;
  delete fSilicone;
  delete fCoating;
}

//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......

PSFMaterials *PSFMaterials::GetInstance()
{
  if (!fInstance)
  {
    fInstance = new PSFMaterials();
  }
  return fInstance;
}

//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......

G4Material *PSFMaterials::GetMaterial(const G4String material)
{
  G4Material *mat = fNistMan->FindOrBuildMaterial(material);

  if (!mat)
    mat = G4Material::GetMaterial(material);
  if (!mat)
  {
    G4ExceptionDescription ed;
    ed << "Material " << material << " not found!";
    G4Exception("PSFMaterials::GetMaterial", "", FatalException, ed);
  }

  return mat;
}

//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......

void PSFMaterials::CreateMaterials()
{
  G4double density;
  G4int ncomponents;
  G4double fractionmass;
  std::vector<G4int> natoms;
  std::vector<G4double> fractionMass;
  std::vector<G4String> elements;

  // Materials Definitions
  // =====================

  //--------------------------------------------------
  // Vacuum
  //--------------------------------------------------

  fNistMan->FindOrBuildMaterial("G4_Galactic");

  //--------------------------------------------------
  // Air
  //--------------------------------------------------

  fAir = fNistMan->FindOrBuildMaterial("G4_AIR");
  //--------------------------------------------------
  // Aluminium
  //--------------------------------------------------

  fNistMan->FindOrBuildMaterial("G4_Al");
  //--------------------------------------------------
  // PMMA(涂层)
  //--------------------------------------------------

  elements.push_back("C");
  natoms.push_back(5);
  elements.push_back("H");
  natoms.push_back(8);
  elements.push_back("O");
  natoms.push_back(2);

  density = 1.190 * g / cm3;

  fPMMA = fNistMan->ConstructNewMaterial("PMMA", elements, natoms, density);

  elements.clear();
  natoms.clear();
  //--------------------------------------------------
  // Silicone (Template for Optical Grease)硅树脂
  //--------------------------------------------------

  elements.push_back("C");
  natoms.push_back(2);
  elements.push_back("H");
  natoms.push_back(6);

  density = 1.060 * g / cm3;

  fSilicone = fNistMan->ConstructNewMaterial("Silicone", elements, natoms, density);

  elements.clear();
  natoms.clear();

  //--------------------------------------------------
  // Polystyrene（光纤核心）
  //--------------------------------------------------

  elements.push_back("C");
  natoms.push_back(8);
  elements.push_back("H");
  natoms.push_back(8);

  density = 1.050 * g / cm3;

  fPolystyrene =
      fNistMan->ConstructNewMaterial("Polystyrene", elements, natoms, density);

  elements.clear();
  natoms.clear();

  // ------------ Generate & Add Material Properties Table ------------
  //

  std::vector<G4double> energy = {
      2.00 * eV, 2.03 * eV, 2.06 * eV, 2.09 * eV, 2.12 * eV, 2.15 * eV, 2.18 * eV, 2.21 * eV, 2.24 * eV, 2.27 * eV,
      2.30 * eV, 2.33 * eV, 2.36 * eV, 2.39 * eV, 2.42 * eV, 2.45 * eV, 2.48 * eV, 2.51 * eV, 2.54 * eV, 2.57 * eV,
      2.60 * eV, 2.63 * eV, 2.66 * eV, 2.69 * eV, 2.72 * eV, 2.75 * eV, 2.78 * eV, 2.81 * eV, 2.84 * eV, 2.87 * eV,
      2.90 * eV, 2.93 * eV, 2.96 * eV, 2.99 * eV, 3.02 * eV, 3.05 * eV, 3.08 * eV, 3.11 * eV, 3.14 * eV, 3.17 * eV,
      3.20 * eV, 3.23 * eV, 3.26 * eV, 3.29 * eV, 3.32 * eV, 3.35 * eV, 3.38 * eV, 3.41 * eV, 3.44 * eV, 3.47 * eV};
  // 波长:620nm-357nm
  std::vector<G4double> energySmall = {2.0 * eV, 3.47 * eV};

  //--------------------------------------------------
  // Air
  //--------------------------------------------------

  std::vector<G4double> refractiveIndex = {1.0, 1.0};
  auto mpt = new G4MaterialPropertiesTable();
  mpt->AddProperty("RINDEX", energySmall, refractiveIndex); // 折射率
  fAir->SetMaterialPropertiesTable(mpt);

  //--------------------------------------------------
  //  PMMA(涂层)
  //--------------------------------------------------

  std::vector<G4double> refractiveIndexClad1 = {1.49, 1.49};
  // std::vector<G4double> absClad1 = {15.5 * cm, 15.5 * cm};
  // std::vector<G4double> absClad1 = {2.67 * m, 2.67 * m};
  std::vector<G4double> absClad1 = {1.0 * mm, 1.0 * mm};
  // Add entries into properties table
  // 添加随波长变化的光学属性 添加本征属性
  auto Clad1 = new G4MaterialPropertiesTable();
  Clad1->AddProperty("RINDEX", energySmall, refractiveIndexClad1); // 折射率
  Clad1->AddProperty("ABSLENGTH", energySmall, absClad1);          // 吸收长度

  fPMMA->SetMaterialPropertiesTable(Clad1);
  //--------------------------------------------------
  // Silicone 硅树脂
  //--------------------------------------------------

  std::vector<G4double> refractiveIndexSilicone = {1.46, 1.46};

  // Add entries into properties table
  auto mptSilicone = new G4MaterialPropertiesTable();
  mptSilicone->AddProperty("RINDEX", energySmall, refractiveIndexSilicone);
  mptSilicone->AddProperty("ABSLENGTH", energySmall, absClad1);

  fSilicone->SetMaterialPropertiesTable(mptSilicone);
  //--------------------------------------------------
  //  Polystyrene 聚苯乙烯（光纤核心）
  //--------------------------------------------------

  std::vector<G4double> refractiveIndexPS = {1.59, 1.59};
  // std::vector<G4double> absPS = {4.67 * m, 4.67 * m};
  std::vector<G4double> absPS = {2.67 * m, 2.67 * m};
  std::vector<G4double> scintilFast = {
      0.00083, 0.00051, 0.00073, 0.00089, 0.00104, 0.00116, 0.00125, 0.00154, 0.00190, 0.00223,
      0.00264, 0.00324, 0.00396, 0.00481, 0.00565, 0.00664, 0.00799, 0.00955, 0.01159, 0.01385,
      0.01634, 0.01949, 0.02291, 0.02695, 0.03147, 0.03660, 0.04258, 0.04906, 0.05584, 0.06232,
      0.06868, 0.07491, 0.07993, 0.08445, 0.08468, 0.07895, 0.05650, 0.02098, 0.00382, 0.00046,
      0.00051, 0.00058, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000};
  // std::vector<G4double> absPS = {
  //     5.40 * m, 5.40 * m, 5.40 * m, 5.40 * m, 5.40 * m, 5.40 * m, 5.40 * m, 5.40 * m, 5.40 * m, 5.40 * m,
  //     5.40 * m, 5.40 * m, 5.40 * m, 5.40 * m, 5.40 * m, 5.40 * m, 5.40 * m, 5.40 * m, 5.40 * m, 5.40 * m,
  //     5.40 * m, 5.40 * m, 5.40 * m, 5.40 * m, 5.40 * m, 5.40 * m, 5.40 * m, 5.40 * m, 5.40 * m, 1.10 * m,
  //     1.10 * m, 1.10 * m, 1.10 * m, 1.10 * m, 1.10 * m, 1.10 * m, 1.0 * mm, 1.0 * mm, 1.0 * mm, 1.0 * mm,
  //     1.0 * mm, 1.0 * mm, 1.0 * mm, 1.0 * mm, 1.0 * mm, 1.0 * mm, 1.0 * mm, 1.0 * mm, 1.0 * mm, 1.0 * mm
  //     };
  // std::vector<G4double> emissionFib = {
  //     0.05, 0.10, 0.30, 0.50, 0.75, 1.00, 1.50, 1.85, 2.30, 2.75,
  //     3.25, 3.80, 4.50, 5.20, 6.00, 7.00, 8.50, 9.50, 11.1, 12.4,
  //     12.9, 13.0, 12.8, 12.3, 11.1, 11.0, 12.0, 11.0, 17.0, 16.9,
  //     15.0, 9.00, 2.50, 1.00, 0.05, 0.00, 0.00, 0.00, 0.00, 0.00,
  //     0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00
  //     };
  // Add entries into properties table
  auto mptPolystyrene = new G4MaterialPropertiesTable();
  // 添加随波长变化的光学属性 添加本征属性
  mptPolystyrene->AddProperty("RINDEX", energySmall, refractiveIndexPS);       // 折射率
  mptPolystyrene->AddProperty("ABSLENGTH", energySmall, absPS);                // 吸收长度
  mptPolystyrene->AddProperty("SCINTILLATIONCOMPONENT1", energy, scintilFast); // 发射光谱
  // mptPolystyrene->AddProperty("WLSABSLENGTH", energy, absPS);
  // mptPolystyrene->AddProperty("WLSCOMPONENT", energy, emissionFib);
  // mptPolystyrene->AddConstProperty("WLSTIMECONSTANT", 0.5 * ns);
  mptPolystyrene->AddConstProperty("SCINTILLATIONYIELD", 8000 / MeV);       // 光产额
  mptPolystyrene->AddConstProperty("RESOLUTIONSCALE", 1.0);                 // 本征分辨
  mptPolystyrene->AddConstProperty("SCINTILLATIONTIMECONSTANT1", 2.8 * ns); // 衰减时间常数
  mptPolystyrene->AddConstProperty("SCINTILLATIONYIELD1", 1.);              // 相对产率
  fPolystyrene->SetMaterialPropertiesTable(mptPolystyrene);

  // Set the Birks Constant for the Polystyrene scintillator
  fPolystyrene->GetIonisation()->SetBirksConstant(0.126 * mm / MeV);
}
